package com.supercube.sport.yoga.service.impl;

import com.supercube.common.utils.DateUtils;
import com.supercube.common.utils.StringUtils;
import com.supercube.sport.yoga.bo.BookingCourseBO;
import com.supercube.sport.yoga.bo.BookingPersonalCourseBO;
import com.supercube.sport.yoga.bo.ClassTableInfoBO;
import com.supercube.sport.yoga.bo.PersonalCourseBO;
import com.supercube.sport.yoga.dao.ClassInfoMapper;
import com.supercube.sport.yoga.dao.CourseBasicInfoMapper;
import com.supercube.sport.yoga.domain.ClassInfoDTO;
import com.supercube.sport.yoga.service.ClassTableInfo;
import com.supercube.sport.yoga.service.SiteInfoService;
import com.supercube.sport.yoga.utils.UserUtils;
import com.supercube.sport.yoga.vo.CardSupportVenues;
import com.supercube.sport.yoga.vo.ClassTableInfoVO;
import com.supercube.sport.yoga.vo.CourseBasicInfoVO;
import com.supercube.sport.yoga.vo.CourseSupportCardInfoVO;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ClassTableInfoImpl implements ClassTableInfo {

    @Autowired
    private ClassInfoMapper classInfoMapper;

    @Autowired
    CourseBasicInfoMapper courseBasicInfoMapper;

    @Autowired
    SiteInfoService siteInfoService;

    @Override
    public int save(ClassInfoDTO dto) {
        if (!isScheduleForSite(dto.getDate(), dto.getOpeningTimeHour(), dto.getOpeningTime(), dto.getSiteId())) {//场地不可用
            return 1;
        }
        if (!isScheduleForCoach(dto.getDate(), dto.getCoachId(), dto.getOpeningTimeHour(), dto.getOpeningTime())) {//该时间段，教练已有排期
            return 2;
        }
        return classInfoMapper.insert(dto);
    }

    @Override
    public int update(ClassInfoDTO dto) {
        return classInfoMapper.updateByPrimaryKeySelective(dto);
    }

    @Override
    public int deleteClassTableInfoById(String id) {
        return classInfoMapper.deleteByPrimaryKey(id);
    }

    @Override
    public ClassTableInfoVO queryClassTableInfoById(String id) {
        return classInfoMapper.selectByPrimaryKey(id);
    }

    @Override
    public List<ClassTableInfoVO> queryClassTableInfoList(ClassTableInfoBO bo) {
        return classInfoMapper.queryClassTableInfoList(bo);
    }

    @Override
    public List<ClassTableInfoVO> queryPrivateAppointmentClass(BookingCourseBO bo) {

        return classInfoMapper.selectPrivateAppointmentClass(bo.getMemberId(), bo.getCoachId(), bo.getDate(), bo.getCourseId());
    }

    @Override
    @Transactional
    public Integer savePersonalClassTable(BookingPersonalCourseBO bo) {
        String startDate = bo.getStartDate();
        String endDate = bo.getEndDate();
        List<ClassInfoDTO> dtoList = new ArrayList<>();
        while (!startDate.equals(endDate)) {
            if (bo.getWeeks().contains(DateUtils.dateToWeek(startDate))) {
                List<PersonalCourseBO> courseBOList = bo.getCourseBOList();
                for (PersonalCourseBO courseBO : courseBOList) {
                    CourseBasicInfoVO courseBasicInfoVO = courseBasicInfoMapper.selectByPrimaryKey(courseBO.getCourseId());
                    if (!isPersonalScheduleForCoach(startDate, courseBasicInfoVO, bo)) {
                        return 2;
                    }
                    ClassInfoDTO dto = new ClassInfoDTO();
                    try {
                        BeanUtils.copyProperties(dto, courseBasicInfoVO);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                    dto.setId(UUID.randomUUID().toString());
                    dto.setMaximumAttendance(bo.getMaximumAttendance() + "");
                    dto.setStatus("1");
                    dto.setDate(startDate);
                    dto.setCoachId(courseBasicInfoVO.getCoachId());
                    dto.setCourseId(courseBO.getCourseId());
                    dto.setOpeningTimeHour(bo.getStartTimeHour());
                    dto.setOpeningTime(bo.getStartTimeMinute());
                    dto.setEndTime(bo.getEndTimeHour() + ":" + bo.getEndTimeMinute());
                    dto.setTimeBetweenClasses(bo.getTimeBetweenClasses());
                    dto.setVenueId(bo.getVenueId());
                    dto.setTimesPeople1to1("1");
                    dto.setTimesPeople1to2("1");
                    dto.setTimesPeople1to3("1");
                    dto.setCostPerClassPerson1to1(courseBO.getSellPrice1V1() + "");
                    dto.setCostPerClassPerson1to2(courseBO.getSellPrice1V2() + "");
                    dto.setCostPerClassPerson1to3(courseBO.getSellPrice1V3() + "");
                    UserUtils.setRecordBase(dto);
                    dtoList.add(dto);
                }
            }
            startDate = DateUtils.getNextDate(startDate);
        }
        if (CollectionUtils.isNotEmpty(dtoList)) {
            dtoList.forEach(dto -> classInfoMapper.insert(dto));
        }
        return 0;
    }

    @Override
    @Transactional
    public Integer saveClassTableInfo(List<BookingCourseBO> bos) {
        List<ClassInfoDTO> dtoList = new ArrayList<>();
        for (BookingCourseBO bo : bos) {
            if (bo.getCoachId() != null && StringUtils.isNotEmpty(bo.getCourseId()) && StringUtils.isNotEmpty(bo.getSiteId())) {
                CourseBasicInfoVO vo = courseBasicInfoMapper.selectByPrimaryKey(bo.getCourseId());
                if (!isScheduleForSite(bo.getDate(), bo.getOpeningTimeHour(), bo.getOpeningTime(), bo.getSiteId())) {//场地不可用
                    return 1;
                }
                if (!isScheduleForCoach(bo.getDate(), vo.getCoachId(), bo.getOpeningTimeHour(), bo.getOpeningTime())) {//该时间段，教练已有排期
                    return 2;
                }
                ClassInfoDTO dto = new ClassInfoDTO();
                try {
                    BeanUtils.copyProperties(dto, vo);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
                dto.setId(UUID.randomUUID().toString());
                dto.setStatus("1");
                dto.setDate(bo.getDate());
                dto.setCoachId(bo.getCoachId());
                dto.setCourseId(bo.getCourseId());
                dto.setOpeningTimeHour(bo.getOpeningTimeHour());
                dto.setOpeningTime(bo.getOpeningTime());
                dto.setSeatTableTemplate(bo.getSeatTableTemplate());
                dto.setVenueId(bo.getVenueId());
                dto.setSiteId(bo.getSiteId());
                UserUtils.setRecordBase(dto);
                dtoList.add(dto);
            }
        }
        if (CollectionUtils.isNotEmpty(dtoList)) {
            dtoList.forEach(dto -> classInfoMapper.insert(dto));
        }
        return 0;
    }

    @Override
    public List<CourseSupportCardInfoVO> queryAllCardByCourseId(String courseId, String cardName, String cardType) {
        List<CardSupportVenues> list = classInfoMapper.selectCardSupportVenuesList();
        Map<String, List<CardSupportVenues>> listMap = list
                .stream()
                .collect(Collectors.groupingBy(CardSupportVenues::getCardId));
        List<CourseSupportCardInfoVO> vos = classInfoMapper.selectAllCardByCourseId(courseId, cardName, cardType);
        vos.forEach(vo -> {
            List<CardSupportVenues> csv = listMap.get(vo.getCardId());
            if (CollectionUtils.isNotEmpty(csv)) {
                Map<String, List<CardSupportVenues>> collect = csv.stream().collect(Collectors.groupingBy(CardSupportVenues::getVenueName));
                vo.setCardSupportVenuesList(collect.keySet());
            }
        });
        return vos;
    }

    private boolean isScheduleForCoach(String date, Long coachId, String startTimeHour, String startTimeMinute) {
        List<ClassTableInfoVO> classTableInfoVOS = classInfoMapper.selectCanUseCoachByCoachDate(coachId, date);
        return getCanSchedule(startTimeHour, startTimeMinute, classTableInfoVOS);
    }

    //
    private boolean isScheduleForSite(String date, String startTimeHour, String startTimeMinute, String siteId) {
        List<ClassTableInfoVO> classTableInfoVOS = classInfoMapper.selectCanUseSiteBySiteDate(siteId, date);
        return getCanSchedule(startTimeHour, startTimeMinute, classTableInfoVOS);
    }

    private boolean getCanSchedule(String startTimeHour, String startTimeMinute, List<ClassTableInfoVO> classTableInfoVOS) {
        if (CollectionUtils.isEmpty(classTableInfoVOS)) {
            return true;
        }
        Date nowTimeUp = DateUtils.formatStrDateHHmm(startTimeHour + ":" + startTimeMinute);
        Date nowTimeDown = DateUtils.formatStrDateHHmm(
                DateUtils.getDate(
                        DateUtils.formatStrDateHHmm(startTimeHour + ":" + startTimeMinute),
                        "HH:mm",
                        Integer.parseInt("60"),
                        Calendar.MINUTE));
        for (ClassTableInfoVO classTableInfoVO : classTableInfoVOS) {
            String openingTimeHour = classTableInfoVO.getOpeningTimeHour();
            String openingTime = classTableInfoVO.getOpeningTime();
            String courseDuration = classTableInfoVO.getCourseDuration();//课时时长
            Date startTime = DateUtils.formatStrDateHHmm(openingTimeHour + ":" + openingTime);
            Date endTime = DateUtils.formatStrDateHHmm(
                    DateUtils.getDate(
                            DateUtils.formatStrDateHHmm(openingTimeHour + ":" + openingTime),
                            "HH:mm",
                            Integer.parseInt(courseDuration),
                            Calendar.MINUTE));
            if (DateUtils.isEffectiveDate(nowTimeUp, startTime, endTime)
                    || DateUtils.isEffectiveDate(nowTimeDown, startTime, endTime)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 私教时，教练是否满足增加排期
     *
     * @param date
     * @param bo
     * @return
     */
    public boolean isPersonalScheduleForCoach(String date, CourseBasicInfoVO vo, BookingPersonalCourseBO bo) {
        List<ClassTableInfoVO> classTableInfoVOS = classInfoMapper.selectCanUseCoachByCoachDate(vo.getCoachId(), date);
        return getCanPersonalSchedule(bo, classTableInfoVOS);
    }

    private boolean getCanPersonalSchedule(BookingPersonalCourseBO bo, List<ClassTableInfoVO> classTableInfoVOS) {
        if (CollectionUtils.isEmpty(classTableInfoVOS)) {
            return true;
        }
        String startTimeHour = bo.getStartTimeHour();
        String startTimeMinute = bo.getStartTimeMinute();
        String endTimeHour = bo.getEndTimeHour();
        String endTimeMinute = bo.getEndTimeMinute();
        Date nowTimeUp = DateUtils.formatStrDateHHmm(startTimeHour + ":" + startTimeMinute);
        Date nowTimeDown = DateUtils.formatStrDateHHmm(endTimeHour + ":" + endTimeMinute);
        for (ClassTableInfoVO classTableInfoVO : classTableInfoVOS) {
            String openingTimeHour = classTableInfoVO.getOpeningTimeHour();
            String openingTime = classTableInfoVO.getOpeningTime();
            String courseDuration = classTableInfoVO.getCourseDuration();//课时时长
            Date startTime = DateUtils.formatStrDateHHmm(openingTimeHour + ":" + openingTime);
            Date endTime = DateUtils.formatStrDateHHmm(
                    DateUtils.getDate(
                            DateUtils.formatStrDateHHmm(openingTimeHour + ":" + openingTime),
                            "HH:mm",
                            Integer.parseInt(courseDuration),
                            Calendar.MINUTE));
            if (DateUtils.isEffectiveDate(nowTimeUp, startTime, endTime)
                    || DateUtils.isEffectiveDate(nowTimeDown, startTime, endTime)) {
                return false;
            }
        }
        return true;
    }

}
